﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using nl.tno.ict.multitouch.wpfmultitouch.controls;
using TouchLibEvents;
using nl.tno.ict.multitouch.wpfmultitouch.events;
using System.Collections;
using System.Collections.Generic;

namespace nl.tno.ict.multitouch.wpfmultitouch
{
    public class TouchManagerScroll : ITouchManager
    {
        private FingerObject _lastpos;
        private FrameworkElement _element;
        private Point _scale;
        private Hashtable _timerTable = new Hashtable();

        public event Events.TouchEventHandler NewTouch;
        public event Events.TouchEventHandler UpdateTouch;
        public event Events.TouchEventHandler RemoveTouch;

        #region Properties

        /// <summary>
        /// Gets the amount of fingers touching the object
        /// </summary>
        public int FingerCount { get { return 1; } }

        public bool CanBeClicked
        {
            get { return (bool)_element.GetValue(MTProperties.CanBeClickedProperty); }
            set { _element.SetValue(MTProperties.CanBeClickedProperty, value); }
        }

        public bool CanBeDragged
        {
            get { return (bool)_element.GetValue(MTProperties.CanBeDraggedProperty); }
            set { _element.SetValue(MTProperties.CanBeDraggedProperty, value); }
        }

        public bool CanBeScaled
        {
            get { return (bool)_element.GetValue(MTProperties.CanBeScaledProperty); }
            set { _element.SetValue(MTProperties.CanBeScaledProperty, value); }
        }

        public bool CanBeRotated
        {
            get { return (bool)_element.GetValue(MTProperties.CanBeRotatedProperty); }
            set { _element.SetValue(MTProperties.CanBeClickedProperty, value); }
        }

        public bool IsScaling
        {
            get { return (bool)_element.GetValue(MTProperties.IsScalingProperty); }
            set { _element.SetValue(MTProperties.IsScalingProperty, value); }
        }

        public bool IsDragging
        {
            get { return (bool)_element.GetValue(MTProperties.IsDraggingProperty); }
            set { _element.SetValue(MTProperties.IsDraggingProperty, value); }
        }

        public bool IsRotating
        {
            get { return (bool)_element.GetValue(MTProperties.IsDraggingProperty); }
            set { _element.SetValue(MTProperties.IsDraggingProperty, value); }
        }
        /// <summary>
        /// Gets or sets the onTop property. The z-index changes when a finger hits an object.
        /// </summary>
        public bool OnTop
        {
            get { return (bool)_element.GetValue(MTProperties.OnTopProperty); }
            set { _element.SetValue(MTProperties.OnTopProperty, value); }
        }

        #endregion

        /// <summary>
        /// The touchmanager scroll is used for elements who don't have a parent, or the parent is the same of the element.
        /// This touchmanager does not support any moving methods. 
        /// </summary>
        /// <param name="element"></param>
        public TouchManagerScroll(FrameworkElement element)//Verandert in FrameworkElement, er kunnen een aantal methoden verdwijnen!
        {
            _element = element;
            _scale = new Point(1.0, 1.0);
        }
        
        /// <summary>
        /// This method will be used when a new finger hits the surface
        /// </summary>
        /// <param name="obj"></param>
        public void NewFinger(Touch obj)
        {
            _element.Focus();

            MouseButtonEventArgs args = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
            args.RoutedEvent = FrameworkElement.MouseDownEvent;
            _element.RaiseEvent(args);

            MouseEventArgs mea = new MouseEventArgs(Mouse.PrimaryDevice, 1,Stylus.CurrentStylusDevice);
            mea.RoutedEvent = FrameworkElement.MouseEnterEvent;
            _element.RaiseEvent(mea);

            //Set fingerCount var
            if (_element is MTObject)
                ((MTObject)_element).FingerCount = 1;

            _lastpos = new FingerObject() { CurrentPosition = new Point(0.0, 0.0) };

            if (_element is MTRadioButton || _element is MTCheckBox)
            {
               // MouseEventArgs mea = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
                mea.RoutedEvent = MTButton.ClickEvent;
                _element.RaiseEvent(mea);
            }
        }

        /// <summary>
        /// When a finger leaves the object this method will be used
        /// </summary>
        /// <param name="fo"></param>
        public void RemoveFinger(Touch t)
        {
            FingerObject fo = t.Finger;
             MouseEventArgs args = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
            args.RoutedEvent = FrameworkElement.MouseLeaveEvent;
            _element.RaiseEvent(args);

            //Set fingerCount var
            if (_element is MTObject)
                ((MTObject)_element).FingerCount = 0;
        }

        /// <summary>
        /// When a finger raises this method will be used
        /// </summary>
        /// <param name="fo"></param>
        public void FingerRaised(FingerObject fo)
        {
            //Remove finger from list

            MouseEventArgs args = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
            args.RoutedEvent = FrameworkElement.MouseLeaveEvent;
            _element.RaiseEvent(args);

            MouseButtonEventArgs mbe = new MouseButtonEventArgs(Mouse.PrimaryDevice, 1, MouseButton.Left);
            mbe.RoutedEvent = FrameworkElement.MouseUpEvent;
            _element.RaiseEvent(mbe);

            //Set fingerCount var
            if (_element is MTObject)
                ((MTObject)_element).FingerCount = 0;
        }
        /// <summary>
        /// Set new position of a existing finger and do some scaling, rotating and draggin 
        /// </summary>
        /// <param name="FingerNewPos">The new position of a finger</param>
        public void UpdateFinger(Touch t, List<TuioMoveFingerEventArgs> history)
        {
            FingerObject FingerNewPos = t.Finger;
            _scale.X = 1.0;
            _scale.Y = 1.0;
            double angle = calculateRotate(_element);
            FingerObject temp = null;
            
            if (angle >= 0 && angle < 90)
                temp = new FingerObject() { CurrentPosition = new Point((((angle % 90) / 90) * FingerNewPos.CurrentPosition.Y) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.X), (((angle % 90) / 90) * FingerNewPos.CurrentPosition.X * -1) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.Y)) };
            else if (angle >= 90 && angle < 180)
                temp = new FingerObject() { CurrentPosition = new Point((((angle % 90) / 90) * FingerNewPos.CurrentPosition.X * -1) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.Y), (((angle % 90) / 90) * FingerNewPos.CurrentPosition.Y * -1) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.X * -1)) };
            else if (angle >= 180 && angle < 270)
                temp = new FingerObject() { CurrentPosition = new Point((((angle % 90) / 90) * FingerNewPos.CurrentPosition.Y * -1) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.X * -1), (((angle % 90) / 90) * FingerNewPos.CurrentPosition.X) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.Y * -1)) };
            else if (angle >= 270 && angle < 360)
                temp = new FingerObject() { CurrentPosition = new Point((((angle % 90) / 90) * FingerNewPos.CurrentPosition.X) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.Y * -1), (((angle % 90) / 90) * FingerNewPos.CurrentPosition.Y) + (((90 - (angle % 90)) / 90) * FingerNewPos.CurrentPosition.X)) };
            
            if (_lastpos.CurrentPosition.X != 0.0)
            {
                MouseEventArgs args = new MouseEventArgs(Mouse.PrimaryDevice, 1, Stylus.CurrentStylusDevice);
                args.RoutedEvent = FrameworkElement.MouseMoveEvent;
                _element.RaiseEvent(args);

                DragDeltaEventArgs dde = new DragDeltaEventArgs((temp.CurrentPosition.X - _lastpos.CurrentPosition.X)/_scale.X, (temp.CurrentPosition.Y - _lastpos.CurrentPosition.Y)/_scale.Y);
                dde.RoutedEvent = Thumb.DragDeltaEvent;
                _element.RaiseEvent(dde);

                if ((_element is MTGridSplitter) || (_element is Thumb))
                {
                    DragStartedEventArgs dsea = new DragStartedEventArgs((temp.x - _lastpos.CurrentPosition.X)/_scale.X, (temp.y - _lastpos.CurrentPosition.Y)/_scale.Y);
                    dsea.RoutedEvent = Thumb.DragStartedEvent;
                    _element.RaiseEvent(dsea);
                }
            }
            _lastpos = temp;
        }

        private double calculateRotate(DependencyObject element)
        {
            double _angle = 0.0;
            while (true)
            {
                element = VisualTreeHelper.GetParent(element);
                if (element != null && element is FrameworkElement)
                {
                    TransformGroup transformGroup = ((FrameworkElement)element).LayoutTransform as TransformGroup;
                    if (transformGroup == null)
                    {
                        transformGroup = ((FrameworkElement)element).RenderTransform as TransformGroup;
                    }
                    if (transformGroup != null && transformGroup.Children.Count > 0)
                    {
                        foreach (Transform trans in transformGroup.Children)
                        {
                            if (trans is RotateTransform)
                            {
                                _angle += ((RotateTransform)trans).Angle;
                            }
                            if (trans is ScaleTransform)
                            {
                                _scale.X *= ((ScaleTransform)trans).ScaleX;
                                _scale.Y *= ((ScaleTransform)trans).ScaleY;
                            }
                        }
                    }
                }
                if (element == null)
                    break;
            }
            if (_angle < 0)
                return 360 + (_angle % 360);
            return _angle = (_angle % 360);
        }

        #region ITouchManager Members


        public event Events.TouchEventHandler TwinClick;

        public event Events.TouchEventHandler DoubleClick;

        #endregion
    }
}
